Passed
Push — master ( a1f273...a92620 )
by EMP
01:14
created

main.js ➔ addMessages   F

Complexity

Conditions 14

Size

Total Lines 47
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 31
dl 0
loc 47
rs 3.6
c 0
b 0
f 0
cc 14

How to fix   Complexity   

Complexity

Complex classes like main.js ➔ addMessages often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"use strict";
2
3
sodium.ready.then(function() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
	if (ok) {
7
		document.getElementById("txt_skey").style.background = "#466";
8
		document.getElementById("txt_skey").maxLength = "64";
9
	} else {
10
		console.log("Failed to load All-Ears");
11
	}
12
});
13
14
function TabState(cur, max, btnDele, btnUpdt) {
15
	this.cur = cur;
16
	this.max = max;
17
	this.btnDele = btnDele;
18
	this.btnUpdt = btnUpdt;
19
}
20
21
const tabs = [
22
	new TabState(0, 0, false, true), // Inbox
23
	new TabState(0, 0, false, true), // Outbx
24
	new TabState(0, 2, true, false), // Write
25
	new TabState(0, 3, false, false), // Notes
26
	new TabState(0, 3, false, true) // Admin
27
];
28
29
let tab = 0;
30
const TAB_INBOX = 0;
31
const TAB_OUTBX = 1;
0 ignored issues
show
Unused Code introduced by
The constant TAB_OUTBX seems to be never used. Consider removing it.
Loading history...
32
const TAB_WRITE = 2;
33
const TAB_NOTES = 3;
34
const TAB_ADMIN = 4;
35
36
// Helper functions
37
function getCountryName(countryCode) {
38
	const opts = document.getElementById("gatekeeper_country");
39
40
	for (let i = 0; i < opts.length; i++) {
41
		if (opts[i].value === countryCode) {
42
			return opts[i].textContent;
43
		}
44
	}
45
46
	return "Unknown countrycode: " + countryCode;
47
}
48
49
function getCountryFlag(countryCode) {
50
	return sodium.to_string(new Uint8Array([
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
51
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
52
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
53
	]));
54
}
55
56
function getMsgId(num) {
57
	let i;
58
	if (ae.GetExtMsgHeaders(num).toLowerCase().slice(0, 11) === "message-id:") {
59
		i = 0;
60
	} else {
61
		i = ae.GetExtMsgHeaders(num).toLowerCase().indexOf("\nmessage-id:");
62
		if (i < 1) return "ERR";
63
		i++;
64
	}
65
66
	const x = ae.GetExtMsgHeaders(num).slice(i + 11).trim();
67
	if (x[0] !== "<") return "ERR2";
68
	return x.slice(1, x.indexOf(">"));
69
}
70
71
function displayMsg(isInt, num) {
72
	document.getElementById("midright").scroll(0, 0);
73
74
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
75
76
	document.getElementById("btn_reply").disabled = false;
77
	document.getElementById("btn_reply").onclick = function() {
78
		document.getElementById("write_recv").value = isInt? ae.GetIntMsgFrom(num) : ae.GetExtMsgFrom(num);
79
		document.getElementById("write_subj").value = "Re: " + (isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num));
80
		document.getElementById("write_rply").textContent = (isInt? "" : getMsgId(num));
81
		document.getElementById("btn_write").click();
82
		document.getElementById("div_write_1").hidden = false;
83
		document.getElementById("div_write_2").hidden = true;
84
		document.getElementById("write_body").focus();
85
		for (const opt of document.getElementById("write_from").options) {
86
			if (opt.value === (isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num))) {
87
				opt.selected = true;
88
			}
89
		}
90
	};
91
92
	document.getElementById("msg").hidden = false;
93
	document.getElementById("msg").getElementsByTagName("h1")[0].textContent = isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num);
94
	document.getElementById("msg").getElementsByTagName("pre")[0].textContent = isInt ? ae.GetIntMsgBody(num) : ae.GetExtMsgBody(num);
95
96
	document.getElementById("readmsg_to").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
97
	document.getElementById("readmsg_date").children[0].textContent = new Date(ts * 1000).toISOString().slice(0, 19).replace("T", " ");
98
99
	if (!isInt) {
100
		document.getElementById("readmsg_ip").hidden = false;
101
		document.getElementById("readmsg_country").hidden = false;
102
		document.getElementById("readmsg_tls").hidden = false;
103
		document.getElementById("readmsg_greet").hidden = false;
104
		document.getElementById("readmsg_timing").hidden = false;
105
		document.getElementById("readmsg_envfrom").hidden = false;
106
107
		const cc = ae.GetExtMsgCountry(num);
108
109
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetExtMsgIp(num);
110
		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
111
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetExtMsgTLS(num);
112
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetExtMsgGreet(num);
113
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
114
115
		let flagText = "";
116
		if (!ae.GetExtMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
117
		if (!ae.GetExtMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
118
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
119
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
120
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
121
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
122
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
123
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
124
	} else {
125
		document.getElementById("readmsg_ip").hidden = true;
126
		document.getElementById("readmsg_country").hidden = true;
127
		document.getElementById("readmsg_tls").hidden = true;
128
		document.getElementById("readmsg_greet").hidden = true;
129
		document.getElementById("readmsg_timing").hidden = true;
130
		document.getElementById("readmsg_envfrom").hidden = true;
131
132
		let symbol = "<span title=\"Invalid level\">&#x26a0;</span>";
133
		if (ae.GetIntMsgFrom(num) === "system") {if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"System\">&#x1f162;</span>";} // S (System)
134
		else if (ae.GetIntMsgLevel(num) === 0) symbol = "<span title=\"Level 0 User\">&#x1f10c;</span>"; // 0
135
		else if (ae.GetIntMsgLevel(num) === 1) symbol = "<span title=\"Level 1 User\">&#x278a;</span>"; // 1
136
		else if (ae.GetIntMsgLevel(num) === 2) symbol = "<span title=\"Level 2 User\">&#x278b;</span>"; // 2
137
		else if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"Administrator\">&#x1f150;</span>"; // A (Admin)
138
		document.getElementById("readmsg_from").innerHTML = symbol + " " + ae.GetIntMsgFrom(num);
139
140
		let flagText = "";
141
		if (!ae.GetIntMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
142
		if (!ae.GetIntMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
143
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
144
	}
145
}
146
147
// Interface
148
function addMsg(isInt, i) {
149
	const inbox = document.getElementById("tbl_inbox");
150
	const sent = document.getElementById("tbl_outbx");
151
152
	const isSent = false; //TODO
153
	const table = isSent ? sent : inbox;
154
155
	const row = table.insertRow(-1);
156
	const cellTime = row.insertCell(-1);
157
	const cellSubj = row.insertCell(-1);
158
	const cellSnd1 = row.insertCell(-1);
159
	const cellSnd2 = row.insertCell(-1);
160
161
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
162
	cellTime.setAttribute("data-ts", ts);
163
	cellTime.textContent = new Date(ts * 1000).toISOString().slice(0, 10);
164
165
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
166
167
	if (isInt) {
168
		cellSnd1.textContent = ae.GetIntMsgFrom(i);
169
		cellSnd1.className = (ae.GetIntMsgFrom(i).length === 16) ? "mono" : "";
170
	} else {
171
		const from1 = ae.GetExtMsgFrom(i);
172
		const from2 = from1.substring(from1.indexOf("@") + 1);
173
		const cc = ae.GetExtMsgCountry(i);
174
175
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
176
177
		const flag = document.createElement("abbr");
178
		flag.textContent = getCountryFlag(cc);
179
		flag.title = getCountryName(cc);
180
		cellSnd2.appendChild(flag);
181
182
		const fromText = document.createElement("span");
183
		fromText.textContent = " " + from2;
184
		cellSnd2.appendChild(fromText);
185
	}
186
187
//	divDel.innerHTML = "<input class=\"delMsg\" type=\"checkbox\" data-id=\"" + ae.GetIntMsgIdHex(i) + "\">";
188
189
	row.onclick = function() {
190
		displayMsg(isInt, i);
191
	};
192
/*
193
	cellDel.children[0].onchange = function() {
194
		if (!divDel.children[0].checked) {
195
			const checkboxes = elmt.getElementsByTagName("input");
196
			let checked = false;
197
198
			for (let j = 0; j < checkboxes.length; j++) {
199
				if (checkboxes[j].checked) {
200
					checked = true;
201
					break;
202
				}
203
			}
204
205
			if (!checked) {
206
				document.getElementById(isSent ? "btn_sentdel" : "btn_msgdel").hidden = true;
207
				return;
208
			}
209
		}
210
211
		document.getElementById(isSent? "btn_sentdel" : "btn_msgdel").hidden = false;
212
	};
213
*/
214
}
215
216
function getRowsPerPage() {
217
	const tbl = document.getElementById("tbl_inbox");
218
	tbl.innerHTML = "";
219
	const row = tbl.insertRow(-1);
220
	const cell = row.insertCell(-1);
221
	cell.textContent = "0";
222
223
	const rowsPerPage = Math.floor(getComputedStyle(document.getElementById("div_inbox")).height.replace("px", "") / getComputedStyle(document.querySelector("#tbl_inbox > tbody > tr:first-child")).height.replace("px", "")) - 1; // -1 allows space for 'load more'
224
	tbl.innerHTML = "";
225
	return rowsPerPage;
226
}
227
228
function addMessages() {
229
	const rowsPerPage = getRowsPerPage();
230
	let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
231
232
	const maxExt = ae.GetExtMsgCount();
233
	const maxInt = ae.GetIntMsgCount();
234
235
	tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt) / rowsPerPage);
236
237
	let numExt = 0;
238
	let numInt = 0;
239
	let numAdd = 0;
240
241
	while (numAdd < rowsPerPage) {
242
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : -1;
243
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : -1;
244
		if (tsInt === -1 && tsExt === -1) break;
245
246
		if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
247
			if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
248
			numInt++;
249
		} else if (tsExt !== -1) {
250
			if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
251
			numExt++;
252
		}
253
	}
254
255
	if (ae.GetReadyMsgKilos() < ae.GetTotalMsgKilos()) {
256
		const inbox = document.getElementById("tbl_inbox");
257
		const row = inbox.insertRow(-1);
258
		const cell = row.insertCell(-1);
259
		cell.textContent = "Load more (" + (ae.GetTotalMsgKilos() - ae.GetReadyMsgKilos()) + " KiB left)";
260
261
		row.onclick = function() {
262
			this.onclick = "";
263
264
			ae.Message_Browse(false, function(successBrowse) {
265
				document.getElementById("tbl_inbox").style.opacity = 1;
266
267
				if (successBrowse) {
268
					addMessages();
269
					if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
270
				}
271
			});
272
		};
273
	}
274
}
275
276
function addNotes() {
277
	const tbl = document.getElementById("tbd_texts");
278
279
	for (let i = 0; i < ae.GetNoteCount(); i++) {
280
		const row = tbl.insertRow(-1);
281
		let cell;
282
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetNoteTime(i) * 1000).toISOString().slice(0, 10);
283
		cell = row.insertCell(-1); cell.textContent = ae.GetNoteTitle(i);
284
		cell = row.insertCell(-1); cell.textContent = ""; // Format
285
		cell = row.insertCell(-1); cell.textContent = ""; // Size
286
		cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\">X</button>";
287
	}
288
}
289
290
function updateAddressCounts() {
291
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetAddressLimitNormal(ae.GetUserLevel())).padStart(ae.GetAddressLimitNormal(ae.GetUserLevel()) > 9 ? 5 : 1);
292
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetAddressLimitShield(ae.GetUserLevel())).padStart(ae.GetAddressLimitShield(ae.GetUserLevel()) > 9 ? 5 : 1);
293
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
294
}
295
296
function adjustLevel(pubkey, level, c) {
297
	const fs = document.getElementById("fs_accs");
298
	fs.disabled = true;
299
300
	ae.Account_Update(pubkey, level, function(success) {
301
		fs.disabled = false;
302
303
		if (success) {
304
			c[4].textContent = level;
305
			c[5].children[0].disabled = (level === 3);
306
			c[6].children[0].disabled = (level === 0);
307
		}
308
	});
309
}
310
311
function addAccountToTable(i) {
312
	const tblAccs = document.getElementById("tbd_accs");
313
	const row = tblAccs.insertRow(-1);
314
	let cell;
315
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserPkHex(i);
316
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSpace(i);
317
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserNAddr(i);
318
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSAddr(i);
319
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserLevel(i);
320
321
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">+</button>";
322
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) + 1, c);};
323
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 3);
324
325
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">&minus;</button>";
326
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) - 1, c);};
327
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 0);
328
329
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">X</button>";
330
	cell.children[0].onclick = function() {
331
		const tr = this.parentElement.parentElement;
332
		ae.Account_Delete(tr.cells[0].textContent, function(success) {
333
			if (success) tr.remove();
334
		});
335
	};
336
}
337
338
function reloadAccount() {
339
	// Limits
340
	const tblLimits = document.getElementById("tbl_limits");
341
	for (let i = 0; i < 4; i++) {
342
		tblLimits.rows[i].cells[1].children[0].value = ae.GetStorageLimit(i) + 1;
343
		tblLimits.rows[i].cells[2].children[0].value = ae.GetAddressLimitNormal(i);
344
		tblLimits.rows[i].cells[3].children[0].value = ae.GetAddressLimitShield(i);
345
	}
346
347
	// Accounts
348
	const tblAccs = document.getElementById("tbd_accs");
349
350
	// All: Our account
351
	const row = tblAccs.insertRow(-1);
352
	let cell;
353
	cell = row.insertCell(-1); cell.textContent = ae.GetUserPkHex();
354
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.GetTotalMsgKilos() / 1024);
355
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountNormal();
356
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountShield();
357
	cell = row.insertCell(-1); cell.textContent = ae.GetUserLevel();
358
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\" disabled=\"disabled\">+</button>";
359
360
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_downme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">&minus;</button>";
361
	cell.children[0].onclick = function() {
362
		const newLevel = parseInt(row.cells[4].textContent) - 1;
363
		ae.Account_Update(ae.GetUserPkHex(), newLevel, function(success) {
0 ignored issues
show
Unused Code introduced by
The parameter success is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
364
			row.cells[4].textContent = newLevel;
365
		});
366
	};
367
368
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_killme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">X</button>";
369
	cell.children[0].onclick = function() {
370
		const tr = this.parentElement.parentElement;
0 ignored issues
show
Unused Code introduced by
The constant tr seems to be never used. Consider removing it.
Loading history...
371
		ae.Account_Delete(ae.GetUserPkHex(), function(success) {
0 ignored issues
show
Unused Code introduced by
The parameter success is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
372
			row.remove();
373
		});
374
	};
375
376
	// Admin: Other accounts
377
	if (ae.IsUserAdmin()) {
378
		for (let i = 0; i < ae.Admin_GetUserCount(); i++) {
379
			addAccountToTable(i);
380
		}
381
	}
382
383
	document.getElementById("txt_reg").disabled = !ae.IsUserAdmin();
384
	document.getElementById("btn_reg").disabled = !ae.IsUserAdmin();
385
386
	// Contacts
387
	for (let i = 0; i < ae.GetContactCount(); i++) {
388
		addContact(
389
			ae.GetContactMail(i),
390
			ae.GetContactName(i),
391
			ae.GetContactNote(i)
392
		);
393
	}
394
395
	// Addresses
396
	for (let i = 0; i < ae.GetAddressCount(); i++) {
397
		addAddress(i);
398
	}
399
400
	updateAddressCounts();
401
}
402
403 View Code Duplication
function deleteAddress(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
404
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
405
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
406
407
	let addressToDelete = -1;
408
409
	for (let i = 0; i < ae.GetAddressCount(); i++) {
410
		if (addr === ae.GetAddress(i)) {
411
			addressToDelete = i;
412
			break;
413
		}
414
	}
415
416
	if (addressToDelete === -1) return;
417
418
	ae.Address_Delete(addressToDelete, function(success) {
419
		if (success) {
420
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
421
			document.getElementById("write_from").remove(addressToDelete);
422
			updateAddressCounts();
423
424
			if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) document.getElementById("btn_address_create_normal").disabled = false;
425
			if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) document.getElementById("btn_address_create_shield").disabled = false;
426
427
			ae.Private_Update(function(success2) {
428
				if (!success2) console.log("Failed to update the Private field");
429
430
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
431
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
432
			});
433
		} else {
434
			console.log("Failed to delete address");
435
436
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
437
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
438
		}
439
	});
440
}
441
442 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
443
	let newAddr = "";
444
445
	for (let i = 0; i < 16; i++) {
446
		switch (addr.charAt(i)) {
447
			case '1':
448
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
449
				break;
450
			case '0':
451
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
452
				break;
453
			case 'w':
454
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
455
				break;
456
			default:
457
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
458
		}
459
	}
460
461
	return newAddr;
462
}
463
464
function addAddress(num) {
465
	const addrTable = document.getElementById("tbl_addrs");
466
	const row = addrTable.insertRow(-1);
467
	const cellAddr = row.insertCell(-1);
468
	const cellChk1 = row.insertCell(-1);
469
	const cellChk2 = row.insertCell(-1);
470
	const cellChk3 = row.insertCell(-1);
471
	const cellBtnD = row.insertCell(-1);
472
473
	cellAddr.textContent = ae.GetAddress(num);
474
	cellAddr.onclick = function() {
475
		if (cellAddr.textContent.length === 16)
476
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomainEml());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
477
		else
478
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomainEml());
479
	};
480
481
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
482
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
483
	cellChk3.innerHTML = ae.GetAddressUse_Gk(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
484
485
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
486
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
487
488
	const opt = document.createElement("option");
489
	opt.value = cellAddr.textContent;
490
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomainEml();
491
	document.getElementById("write_from").appendChild(opt);
492
}
493
494
document.getElementById("btn_dele").onclick = function() {
495
	this.blur();
496
497
	if (tab === TAB_WRITE) {
498
		tabs[tab].cur = 0;
499
		updateTab();
500
501
		document.getElementById("write_recv").value = "";
502
		document.getElementById("write_subj").value = "";
503
		document.getElementById("write_body").value = "";
504
505
		document.getElementById("write_recv").focus();
506
	}
507
};
508
509
document.getElementById("btn_updt").onclick = function() {
510
	const btn = this;
511
	btn.disabled = true;
512
	btn.blur();
513
514
	if (tab === TAB_INBOX) {
515
		document.getElementById("tbl_inbox").style.opacity = 0.5;
516
517
		ae.Message_Browse(true, function(successBrowse) {
518
			document.getElementById("tbl_inbox").style.opacity = 1;
519
520
			if (successBrowse) {
521
				addMessages();
522
				addNotes();
523
				btn.disabled = false;
524
			} else {
525
				console.log("Failed to refresh");
526
				btn.disabled = false;
527
			}
528
		});
529
	}
530
};
531
532
function addContact(mail, name, note) {
533
	const tbl = document.getElementById("tbl_ctact");
534
	const row = tbl.insertRow(-1);
535
	const cellMail = row.insertCell(-1);
536
	const cellName = row.insertCell(-1);
537
	const cellNote = row.insertCell(-1);
538
	const cellBtnD = row.insertCell(-1);
539
540
	cellMail.textContent = mail;
541
	cellName.textContent = name;
542
	cellNote.textContent = note;
543
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
544
545
	cellMail.contentEditable = true;
546
	cellName.contentEditable = true;
547
	cellNote.contentEditable = true;
548
549
	cellBtnD.onclick = function() {row.remove();};
550
}
551
552
document.getElementById("btn_newcontact").onclick = function() {
553
	addContact("", "", "");
554
};
555
556
document.getElementById("btn_savecontacts").onclick = function() {
557
	while (ae.GetContactCount() > 0) {
558
		ae.DeleteContact(0);
559
	}
560
561
	for (const row of document.getElementById("tbl_ctact").rows) {
562
		ae.AddContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
563
	}
564
565
	const btn = this;
566
	btn.disabled = true;
567
568
	ae.Private_Update(function(success) {
569
		btn.disabled = false;
570
571
		if (!success) {
572
			console.log("Failed contacts update");
573
		}
574
	});
575
};
576
577
function updateTab() {
578
	switch (tab) {
579
		case TAB_INBOX:
580
			addMessages();
581
		break;
582
583
		case TAB_WRITE:
584
			switch (tabs[tab].cur) {
585
				case 0: // Write
586
					document.getElementById("div_write_1").hidden = false;
587
					document.getElementById("div_write_2").hidden = true;
588
					document.getElementById("write_body").focus();
589
				break;
590
591
				case 1: // Verify
592
					ae.Address_Lookup(document.getElementById("write_recv").value, function(pk) {
593
						if (pk) {
594
							document.getElementById("div_write_1").hidden = true;
595
							document.getElementById("div_write_2").hidden = false;
596
597
							document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.GetDomainEml();
598
							document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
599
							document.getElementById("write2_pkey").textContent = sodium.to_hex(pk);
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
600
601
							document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
602
							document.getElementById("write2_rply").textContent = document.getElementById("write_rply").textContent;
603
							document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
604
						} else {
605
							console.log("Failed lookup");
606
						}
607
					});
608
				break;
609
610
				case 2: // Send
611
					ae.Message_Create(
612
						document.getElementById("write_subj").value,
613
						document.getElementById("write_body").value,
614
						document.getElementById("write_from").value,
615
						document.getElementById("write_recv").value,
616
						document.getElementById("write_rply").textContent,
617
						(document.getElementById("write2_recv").textContent.indexOf("@") > 0) ? null : sodium.from_hex(document.getElementById("write2_pkey").textContent),
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
618
						function(success) {
619
							if (success) {
620
								console.log("Sent ok");
621
							} else {
622
								console.log("Failed sending");
623
							}
624
						}
625
					);
626
				break;
627
			}
628
		break;
629
630
		case TAB_NOTES:
631
			for (let i = 0; i <= tabs[tab].max; i++) {
632
				document.getElementById("div_notes").children[i].hidden = (i !== tabs[tab].cur);
633
			}
634
		break;
635
636
		case TAB_ADMIN:
637
			for (let i = 0; i <= tabs[tab].max; i++) {
638
				document.getElementById("div_admin").children[i].hidden = (i !== tabs[tab].cur);
639
			}
640
		break;
641
	}
642
643
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
644
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
645
}
646
647
document.getElementById("btn_left").onclick = function() {
648
	tabs[tab].cur--;
649
	if (tabs[tab].cur === 0) this.disabled = true;
650
	if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
651
	updateTab();
652
	this.blur();
653
};
654
655
document.getElementById("btn_rght").onclick = function() {
656
	tabs[tab].cur++;
657
	if (tabs[tab].cur === tabs[tab].max) this.disabled = true;
658
	document.getElementById("btn_left").disabled = false;
659
	updateTab();
660
	this.blur();
661
};
662
663
const buttons = document.querySelector("#main1 > .top").getElementsByTagName("button");
664
for (let i = 0; i < buttons.length; i++) {
665
	buttons[i].onclick = function() {
666
		tab = i;
667
668
		for (let j = 0; j < buttons.length; j++) {
669
			document.querySelector("#main1 > .mid").children[j].hidden = (tab !== j);
670
			buttons[j].disabled = (tab === j);
671
		}
672
673
		document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
0 ignored issues
show
Bug introduced by
The variable tab is changed as part of the for loop for example by i on line 666. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
674
		document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
675
		document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
676
		document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
677
	};
678
}
679
680
function addressCreate(addr) {
681
	const btnN = document.getElementById("btn_address_create_normal");
682
	const btnS = document.getElementById("btn_address_create_shield");
683
	btnN.disabled = true;
684
	btnS.disabled = true;
685
686
	ae.Address_Create(addr, function(success1) {
687
		if (success1) {
688
			ae.Private_Update(function(success2) {
689
				addAddress(ae.GetAddressCount() - 1);
690
				if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
691
				updateAddressCounts();
692
693
				if (!success2) console.log("Failed to update the Private field");
694
695
				if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) btnN.disabled = false;
696
				if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) btnS.disabled = false;
697
			});
698
		} else {
699
			console.log("Failed to add address");
700
701
			if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) btnN.disabled = false;
702
			if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) btnS.disabled = false;
703
		}
704
	});
705
}
706
707
document.getElementById("btn_address_create_normal").onclick = function() {
708
	if (ae.GetAddressCountNormal() >= ae.GetAddressLimitNormal(ae.GetUserLevel())) return;
709
710
	const txtNewAddr = document.getElementById("txt_address_create_normal");
711
	if (!txtNewAddr.reportValidity()) return;
712
713
	addressCreate(txtNewAddr.value);
714
};
715
716
document.getElementById("btn_address_create_shield").onclick = function() {
717
	if (ae.GetAddressCountShield() >= ae.GetAddressLimitShield(ae.GetUserLevel())) return;
718
719
	addressCreate("SHIELD");
720
};
721
722
document.getElementById("btn_reg").onclick = function() {
723
	const btn = document.getElementById("btn_reg");
724
	const txt = document.getElementById("txt_reg");
725
	if (!txt.reportValidity()) return;
726
	btn.disabled = true;
727
728
	ae.Account_Create(txt.value, function(success) {
729
		if (success) {
730
			addAccountToTable(ae.Admin_GetUserCount() - 1);
731
			txt.value = "";
732
		}
733
734
		btn.disabled = false;
735
	});
736
};
737
738
document.getElementById("chk_downme").onclick = function() {document.getElementById("btn_downme").disabled = !this.checked;};
739
document.getElementById("chk_killme").onclick = function() {document.getElementById("btn_killme").disabled = !this.checked;};
740
741
document.getElementById("btn_notepad_savesep").onclick = function() {
742
	const np = document.getElementById("txt_notepad");
743
	np.disabled = true;
744
745
	ae.Message_StoreT("title", np.value, false, function(success) {
746
		if (success) {
747
			np.value = "";
748
			addNotes();
749
		}
750
751
		console.log("Failed to add text");
752
		np.disabled = false;
753
	});
754
};
755
756
document.getElementById("txt_skey").onkeyup = function(event) {
757
	if (event.key === "Enter") {
758
		event.preventDefault();
759
		document.getElementById("btn_enter").click();
760
	}
761
};
762
763
document.getElementById("btn_enter").onclick = function() {
764
	const txtSkey = document.getElementById("txt_skey");
765
	if (!txtSkey.reportValidity()) return;
766
767
	const btn = this;
768
	btn.disabled = true;
769
	document.getElementById("txt_skey").style.background = "#233";
770
771
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
772
		if (successSetKeys) {
773
			ae.Account_Browse(0, function(successBrowse) {
774
				if (successBrowse) {
775
					txtSkey.value = "";
776
777
					reloadAccount();
778
					document.getElementById("div_begin").hidden = true;
779
					document.getElementById("div_main").style.display = "grid";
780
781
					document.getElementById("btn_updt").click();
782
				} else {
783
					console.log("Failed to enter");
784
					btn.disabled = false;
785
					document.getElementById("txt_skey").style.background = "#466";
786
					txtSkey.focus();
787
				}
788
			});
789
		} else {
790
			console.log("Invalid format for key");
791
			btn.disabled = false;
792
			document.getElementById("txt_skey").style.background = "#466";
793
			txtSkey.focus();
794
		}
795
	});
796
};
797
798
});
799